In [1]:
import sys
import os
sys.path.insert(0, os.path.abspath('../'))
sys.path.insert(0, os.path.abspath('../../'))
sys.path.insert(0, os.path.abspath('/home/hm-tlacherm/qlm_notebooks/notebooks_1.2.1/notebooks/master_thesis_qaoa/'))
sys.path.insert(0, os.path.abspath('/home/hm-tlacherm/qlm_notebooks/notebooks_1.2.1/notebooks/master_thesis_qaoa/ibm/'))
In [2]:
import numpy as np

import qiskit
provider = qiskit.IBMQ.load_account()
from qiskit import Aer
from qiskit.utils import QuantumInstance
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit.algorithms import QAOA
from shared.QiskitMaxcut import *
from ibm.ibm_parameters import *

from matplotlib import pyplot as plt
%matplotlib inline
In [3]:
graph = generate_butterfly_graph(with_weights=True)
max_cut = Maxcut(graph)
max_cut_qubo = max_cut.to_qubo()
print(graph.name)
max_cut.draw()
graph_05_06_02_w
In [4]:
step_size = 0.06
a_gamma = np.arange(-np.pi, np.pi, step_size)
b_beta = np.arange(-np.pi, np.pi, step_size)
In [5]:
len(a_gamma) 
Out[5]:
105
In [6]:
a_gamma, b_beta = np.meshgrid(a_gamma, b_beta)
In [7]:
quantum_instance = QuantumInstance(
                    backend=Aer.get_backend(DEFAULT_QASM_SIMULATOR),
                    shots=SHOTS)
qaoa = QAOA(
            optimizer=COBYLA(maxiter=0),
            quantum_instance=quantum_instance,
            reps=1
            )

op, offset = max_cut_qubo.to_ising()
In [8]:
def maxcut_obj(x, G):
    """
    Given a bitstring as a solution, this function returns
    the number of edges shared between the two partitions
    of the graph.
    
    Args:
        x: str
           solution bitstring
           
        G: networkx graph
        
    Returns:
        obj: float
             Objective
    """
    obj = 0
    for i,j,w in graph.edges.data('weight'):
        if x[i] != x[j]:
            obj -= w
            
    return obj


def compute_expectation(counts, G):
    
    """
    Computes expectation value based on measurement results
    
    Args:
        counts: dict
                key as bitstring, val as count
           
        G: networkx graph
        
    Returns:
        avg: float
             expectation value
    """
    
    avg = 0
    sum_count = 0
    for bitstring, count in counts.items():
        
        obj = maxcut_obj(bitstring, G)
        avg += obj * count
        sum_count += count
        
    return avg/sum_count
In [9]:
def create_cirucit(beta,gamma):
    circuits = qaoa.construct_circuit([beta,gamma], operator=op)
    circuit = circuits[0]
    circuit.measure_all()
    return circuit
In [10]:
landscape = np.zeros(a_gamma.shape)

for i in range(0, len(landscape)):
    circuits = []
    for j in range(0, len(landscape)):
        # create circuits for entire row 
        circuit = create_cirucit(b_beta[i][j], a_gamma[i][j])
        circuits.append(circuit)
    
    # create one job with circuits 
    job_name = f"{graph.name}_row_{i}"
    job = qiskit.execute(circuits, backend=provider.get_backend('ibmq_toronto'), shots=1024)
    job.update_name(job_name)
    print(job_name)
    
    # add results to landscape 
    j = 0
    for count in job.result().get_counts():
        mean = compute_expectation(count, graph)
        landscape[i,j] = mean
        j += 1
graph_05_06_02_w_row_0
graph_05_06_02_w_row_1
graph_05_06_02_w_row_2
graph_05_06_02_w_row_3
graph_05_06_02_w_row_4
graph_05_06_02_w_row_5
graph_05_06_02_w_row_6
graph_05_06_02_w_row_7
graph_05_06_02_w_row_8
graph_05_06_02_w_row_9
graph_05_06_02_w_row_10
graph_05_06_02_w_row_11
graph_05_06_02_w_row_12
graph_05_06_02_w_row_13
graph_05_06_02_w_row_14
graph_05_06_02_w_row_15
graph_05_06_02_w_row_16
graph_05_06_02_w_row_17
graph_05_06_02_w_row_18
graph_05_06_02_w_row_19
graph_05_06_02_w_row_20
graph_05_06_02_w_row_21
graph_05_06_02_w_row_22
graph_05_06_02_w_row_23
graph_05_06_02_w_row_24
graph_05_06_02_w_row_25
graph_05_06_02_w_row_26
graph_05_06_02_w_row_27
graph_05_06_02_w_row_28
graph_05_06_02_w_row_29
graph_05_06_02_w_row_30
graph_05_06_02_w_row_31
graph_05_06_02_w_row_32
graph_05_06_02_w_row_33
graph_05_06_02_w_row_34
graph_05_06_02_w_row_35
graph_05_06_02_w_row_36
graph_05_06_02_w_row_37
graph_05_06_02_w_row_38
graph_05_06_02_w_row_39
graph_05_06_02_w_row_40
graph_05_06_02_w_row_41
graph_05_06_02_w_row_42
graph_05_06_02_w_row_43
graph_05_06_02_w_row_44
graph_05_06_02_w_row_45
graph_05_06_02_w_row_46
graph_05_06_02_w_row_47
graph_05_06_02_w_row_48
graph_05_06_02_w_row_49
graph_05_06_02_w_row_50
graph_05_06_02_w_row_51
graph_05_06_02_w_row_52
graph_05_06_02_w_row_53
graph_05_06_02_w_row_54
graph_05_06_02_w_row_55
graph_05_06_02_w_row_56
graph_05_06_02_w_row_57
graph_05_06_02_w_row_58
graph_05_06_02_w_row_59
graph_05_06_02_w_row_60
graph_05_06_02_w_row_61
graph_05_06_02_w_row_62
graph_05_06_02_w_row_63
graph_05_06_02_w_row_64
graph_05_06_02_w_row_65
graph_05_06_02_w_row_66
graph_05_06_02_w_row_67
graph_05_06_02_w_row_68
graph_05_06_02_w_row_69
graph_05_06_02_w_row_70
graph_05_06_02_w_row_71
graph_05_06_02_w_row_72
graph_05_06_02_w_row_73
graph_05_06_02_w_row_74
graph_05_06_02_w_row_75
graph_05_06_02_w_row_76
graph_05_06_02_w_row_77
graph_05_06_02_w_row_78
graph_05_06_02_w_row_79
graph_05_06_02_w_row_80
graph_05_06_02_w_row_81
graph_05_06_02_w_row_82
graph_05_06_02_w_row_83
graph_05_06_02_w_row_84
graph_05_06_02_w_row_85
graph_05_06_02_w_row_86
graph_05_06_02_w_row_87
graph_05_06_02_w_row_88
graph_05_06_02_w_row_89
graph_05_06_02_w_row_90
graph_05_06_02_w_row_91
graph_05_06_02_w_row_92
graph_05_06_02_w_row_93
graph_05_06_02_w_row_94
graph_05_06_02_w_row_95
graph_05_06_02_w_row_96
graph_05_06_02_w_row_97
graph_05_06_02_w_row_98
graph_05_06_02_w_row_99
graph_05_06_02_w_row_100
graph_05_06_02_w_row_101
graph_05_06_02_w_row_102
graph_05_06_02_w_row_103
graph_05_06_02_w_row_104
In [11]:
print(landscape)
plt.matshow(landscape)
plt.show()
[[-24.75390625 -25.98535156 -26.19726562 ... -25.90625    -25.88769531
  -25.86621094]
 [-24.10839844 -24.04296875 -24.72070312 ... -25.11523438 -24.296875
  -24.58203125]
 [-24.65527344 -24.60351562 -23.72851562 ... -24.52832031 -24.38476562
  -24.30078125]
 ...
 [-24.72460938 -24.09082031 -24.59667969 ... -24.50683594 -23.54980469
  -24.98144531]
 [-24.87792969 -24.59375    -25.26855469 ... -24.07226562 -24.13964844
  -23.86035156]
 [-24.80175781 -24.765625   -24.8203125  ... -23.82519531 -25.09082031
  -24.82617188]]
In [12]:
# Mean of landscape
np.mean(landscape)
Out[12]:
-24.65888950892857
In [13]:
# Minimium 
np.min(landscape)
Out[13]:
-29.044921875
In [14]:
# Display Coordinates of Minimum 
np.unravel_index(np.argmin(landscape), landscape.shape)
Out[14]:
(43, 31)
In [15]:
# Gamma and beta value of Minimium
gamma, beta = np.unravel_index(np.argmin(landscape), landscape.shape)
opt_gamma = gamma * step_size
opt_beta = beta * step_size
print(f"Opt.Gamma: {opt_gamma}, Opt.Beta: {opt_beta}")
Opt.Gamma: 2.58, Opt.Beta: 1.8599999999999999
In [16]:
# Save result matrix 
with open('landscape_toronto_butterfly_weights_results.npy', 'wb') as f:
    np.save(f, landscape)
In [17]:
import plotly.graph_objects as go
In [18]:
# Plot landscape in 3D 
a_gamma = np.arange(0, np.pi, step_size)
b_beta = np.arange(0, np.pi, step_size)
fig = go.Figure(data=go.Surface(z=landscape, x=a_gamma, y=b_beta))

fig.update_traces(contours_z=dict(show=True, usecolormap=True, highlightcolor='limegreen', project_z=True))


fig.update_layout(title="QAOA MaxCut", scene=dict(
    xaxis_title="gamma",
    yaxis_title="beta",
    zaxis_title="mean"
))
In [19]:
# Plot Heatmap 
fig = go.Figure(data=go.Heatmap(z=landscape, x=b_beta, y=a_gamma, type = 'heatmap', colorscale = 'viridis'))

# Update Layout
fig.update_layout(title="QAOA MaxCut", width=700, height=700, xaxis_title="beta", yaxis_title="gamma")

# Display Global Minimium 
fig.add_trace(
    go.Scatter(mode="markers", x=[opt_beta], y=[opt_gamma], marker_symbol=[204], text = [landscape[gamma,beta]],
                   marker_color="red",  hovertemplate="x: %{x}<br>y: %{y}<br> z: %{text:.2f}<extra></extra>", 
                   marker_line_width=1, marker_size=16))
In [20]:
# Display Optimizer Results

# Display path 
#fig.add_trace(
#    go.Scatter(mode="lines", x=gammas, y=betas, marker_symbol=[200],
#                   marker_color="white", marker_line_width=1, marker_size=8)
#)

# Display start point
#fig.add_trace(
#    go.Scatter(mode="markers", x=[gammas[0]], y=[betas[0]], marker_symbol=[204],
#                   marker_color="gray", 
#                   marker_line_width=1, marker_size=16))

# Display end point
#fig.add_trace(
#    go.Scatter(mode="markers", x=[gammas[-1]], y=[betas[-1]], marker_symbol=[204],
#                   marker_color="green", 
#                   marker_line_width=1, marker_size=16))
In [21]:
# Plot Optimizer History
#fig = go.Figure(data=go.Scatter(x=counts, y=values))
#fig.update_layout(xaxis_title="Evaluation Counts", yaxis_title="Evaluated Mean", title="Optimizer")
#fig.show()
In [ ]: